Skip to content

ci(release): Publish to Open VSX and automate releases with release-please - #20

Open
Cyclodex wants to merge 2 commits into
developfrom
claude/issue-18-analysis-j49cia
Open

ci(release): Publish to Open VSX and automate releases with release-please#20
Cyclodex wants to merge 2 commits into
developfrom
claude/issue-18-analysis-j49cia

Conversation

@Cyclodex

@Cyclodex Cyclodex commented Aug 5, 2026

Copy link
Copy Markdown
Member

Closes the distribution gap reported in #18: Cursor, VSCodium, Windsurf, Gitpod and Theia cannot use the Visual Studio Marketplace and install from the Open VSX Registry instead, so the extension was only reachable there by side-loading a .vsix.

No extension code changes were needed. The only marketplace touchpoint is vscode.commands.executeCommand('workbench.extensions.search', ...) in src/utils.ts:94, a built-in command Cursor implements; everything else is stable vscode.extensions.* API on engines.vscode ^1.74.0. This is purely a publishing change.

The release cycle

Every cycle ships twice, and each shipment gets its own Release PR:

Release PR Version Label Merging it publishes
1st odd minor, 1.3.0 pre-release both registries with --pre-release
2nd even minor, 1.4.0 release both registries as the stable version

Nothing anywhere asks which channel a release is — the version decides. publish.yml reads the parity of the minor out of package.json and adds --pre-release on odd, so the number and the published channel cannot disagree. The prerelease workflow inputs were removed for that reason.

The second PR opens by itself: once the odd-minor version is published, the promote job pushes an empty commit carrying Release-As: 1.4.0 and re-runs release-please. It then sits there until you've soaked the pre-release long enough to merge it. You only write a Release-As by hand once per cycle, to open it (Release-As: 1.3.0).

Full flow: merge developmain → pre-release PR → merge → publishes pre-release → release PR appears → merge when happy → publishes release → back-merge maindevelop.

Decisions worth reviewing

Labelled, not renamed. The PR title says chore(main): release 1.3.0; the channel is carried by a label and a comment. That is deliberate — release-please parses its own PR title to recover the version when the PR merges ("must be able to parse out the component and version from the pull request"), so renaming it risks the release not being created at all. If you'd rather have the words in the title, it can be done via pull-request-title-pattern, but that pattern is static — it cannot say "pre-release" on one PR and "release" on the next.

always-bump-patch. Nothing crosses a minor boundary on its own — an automatic feat: bump would walk 1.2.4 → 1.3.0 and silently turn a release into a pre-release. Patch bumps stay inside their channel, which is what you want: 1.3.0 → 1.3.1 is another pre-release.

Conventional commits are now required. The current style is fix(Maintenance) Fixed types — no colon, which release-please cannot parse, so nothing would ever ship. CLAUDE.md now specifies fix(maintenance): Message. This is the one change that silently breaks releases if it isn't followed.

release-please watches main, keeping git-flow. Cost is a main → develop back-merge after each release.

Two caveats documented in RELEASE.md: a fix: landing during the soak folds into the pending release rather than cutting a new pre-release (use Release-As: 1.3.1 if you want one), and the promotion push needs main to allow github-actions[bot] if the branch is protected.

Changes

File
.github/workflows/release-please.yml new — Release PR on push to main, channel labelling, publish, then the promote job that queues the release PR
.github/workflows/publish.yml new — derives the channel from the version, builds one .vsix, publishes to both registries, attaches to the Release
.github/scripts/label-release-pr.sh new — labels/comments the Release PR with its channel
.github/workflows/ci.yml adds workflow_dispatch + a read-only token
release-please-config.json, .release-please-manifest.json new — config at 1.2.4
package.json missing license field, ovsx pinned at 1.1.0, publish:openvsx scripts, release/pre-release cover both registries
.vscodeignore un-ignores CHANGELOG.md so both registries render a changelog tab
RELEASE.md, VERSIONING.md, CLAUDE.md, README.md document the cycle, the setup and where to install

The Release-PR-approval step in release-please.yml is carried over from bexio-chrome-extension, where 1.4.0, 1.5.0 and 1.6.0 all shipped without a build check before it existed.

Before this can publish to Open VSX

The workflow skips the Open VSX step with a warning rather than failing while OVSX_PAT is unset, so Marketplace releases keep flowing meanwhile. To activate it (RELEASE.md → One-time setup):

  1. Log in to open-vsx.org with GitHub.
  2. Create an Eclipse Foundation account and sign the Eclipse Publisher Agreement.
  3. Claim the namespace: npx ovsx create-namespace Soulcode -p <token>.
  4. Add OVSX_PAT as a repository secret (and VSCE_PAT, if CI hasn't published before).

Optionally request namespace ownership on EclipseFdn/open-vsx.org so the extension shows as verified.

Verification

  • actionlint clean on all three workflows; bash -n clean on the script
  • parity logic checked against 1.2.4 / 1.3.0 / 1.3.1 / 1.4.0 / 1.10.2 / 1.11.0 — double-digit minors included
  • 23 unit tests pass
  • vsce package produces a valid .vsix containing LICENSE.txt and changelog.md
  • adding ovsx changed zero existing lockfile versions (74 added, 0 changed, 0 removed)

Not verified: the workflows have not executed on GitHub — release-please.yml only runs on a push to main, so the first real cycle is the first live test of the promote job.

claude added 2 commits August 5, 2026 18:06
…lease

Cursor, VSCodium, Windsurf, Gitpod and Theia cannot use the Visual Studio
Marketplace and install from the Open VSX Registry instead, so the extension
was only reachable there by side-loading a .vsix (issue #18).

Adds the release automation modelled on SoulcodeAgency/bexio-chrome-extension:
release-please opens a Release PR on main, merging it tags + creates the
GitHub Release and triggers publish.yml, which builds one .vsix and ships that
same artifact to both registries.

- release-please uses always-bump-patch, because VERSIONING.md reserves odd
  minors for pre-releases and an automatic minor bump would land on one; a
  minor is requested with Release-As in a commit body
- the Open VSX step is skipped with a warning while OVSX_PAT is unset, so the
  Marketplace release still goes out until the Eclipse publisher agreement and
  the Soulcode namespace are in place
- ci.yml gains workflow_dispatch as the fallback for the Release PR's parked
  build check, and a read-only token
- package.json gains the missing license field, which Open VSX surfaces

No extension code changes: the only marketplace touchpoint is the built-in
workbench.extensions.search command, which Cursor implements.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADtomv1AGke7LABz7GCD7d
Each cycle now produces two Release PRs, in order: the odd-minor pre-release
(1.3.0) and the even-minor release (1.4.0) that follows it. Each PR is labelled
and commented with the channel it will publish to.

- publish.yml derives --pre-release from the parity of the minor in
  package.json instead of taking it as an input, so the version number and the
  published channel cannot disagree; the prerelease inputs are gone
- a promote job opens the second PR by itself: once an odd-minor version is
  published it pushes an empty commit carrying Release-As for the next even
  minor and runs release-please again, because a push made with GITHUB_TOKEN
  does not start a new workflow run
- .github/scripts/label-release-pr.sh labels the Release PR pre-release or
  release. It labels rather than renames on purpose: release-please parses its
  own PR title to recover the version when the PR merges, so editing the title
  risks breaking the release

RELEASE.md documents the cycle, how to cut another pre-release during the soak,
and the branch-protection caveat for the promotion push.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADtomv1AGke7LABz7GCD7d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants